package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"strings"
)

// main
//
//	@Description: 稀疏数组，见图sparsearray.png
//
// 稀疏数组的处理方法：（稀疏数组本质是一种压缩算法）
// 1.记录数组一共有几行几列，有多少个不同的值
// 2.把具有不同值的元素的行列及值记录在一个小规模的数组中，从而缩小程序的空间复杂度
func main() {
	//构建11*11的二维数组
	array := twoDimensionArray()
	//打印原始二维数组
	printTwoDimensionArray(array)

	//生成稀疏数组
	slice := genSparseSlice(array)
	//打印稀疏数组
	printSparseSlice(slice)

	//保存到磁盘
	saveSparseSliceToDisk("sparse.txt", slice)

	//从磁盘读取为稀疏数组
	disk := readSparseSliceFromDisk("sparse.txt")
	//打印稀疏数组
	printSparseSlice(disk)

	//从磁盘读取为二维数组
	fromDisk := readTwoDimensionArrayFromDisk("sparse.txt")
	//打印二维数组
	printTwoDimensionArray(fromDisk)
}

// twoDimensionArray 构建一个原始数组，11*11
//
//	@Description:
//	@return [11][11]int
func twoDimensionArray() [11][11]int {
	var arr [11][11]int
	for row := 0; row < len(arr); row++ {
		cols := arr[row]
		for col := 0; col < len(cols); col++ {
			if (rand.Intn(10)+1)%9 == 0 {
				arr[row][col] = rand.Intn(100)
			}
		}

	}
	return arr
}

// printTwoDimensionArray
//
//	@Description: 打印二维数组
//	@param arr
func printTwoDimensionArray(arr [11][11]int) {
	fmt.Println("--------------原始数组--------------")
	for _, cols := range arr {
		for _, num := range cols {
			fmt.Printf("%d ", num)
		}
		fmt.Println()
	}
}

// genSparseSlice
//
//	@Description: 生成稀疏数组
//	@param array
//	@return []Sparse
func genSparseSlice(array [11][11]int) []Sparse {
	var eleNum int
	var sparseArr = make([]Sparse, 0)
	summary := Sparse{
		Row:   len(array),
		Col:   len(array[0]),
		Value: 0,
	}
	sparseArr = append(sparseArr, summary)
	for i := 0; i < len(array); i++ {
		cols := array[i]
		for j := 0; j < len(cols); j++ {
			if array[i][j] != 0 {
				sp := Sparse{
					Row:   i,
					Col:   j,
					Value: array[i][j],
				}
				sparseArr = append(sparseArr, sp)
				eleNum++
			}
		}
	}
	return sparseArr

}

// printSparseSlice
//
//	@Description: 打印稀疏数组
//	@param slice
func printSparseSlice(slice []Sparse) {
	fmt.Println("--------------稀疏数组--------------")
	for _, v := range slice {
		fmt.Printf("%d %d %d\n", v.Row, v.Col, v.Value)
	}
}

// saveSparseSliceToDisk
//
//	@Description: 将稀疏数组保存到磁盘
//	@param slice
func saveSparseSliceToDisk(path string, slice []Sparse) {
	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println("open file err=", err)
		return
	}
	defer file.Close()
	writer := bufio.NewWriter(file)
	for _, v := range slice {
		writer.Write([]byte(fmt.Sprintf("%d %d %d\n", v.Row, v.Col, v.Value)))
	}
	writer.Flush()

}

// readSparseSliceFromDisk 从磁盘读取稀疏数组
//
//	@Description:
//	@return []Sparse
func readSparseSliceFromDisk(path string) []Sparse {
	var slice = make([]Sparse, 0)
	file, err := os.OpenFile(path, os.O_RDONLY, 0666)
	if err != nil {
		fmt.Println("open file err=", err)
		return nil
	}
	defer file.Close()
	reader := bufio.NewReader(file)

	for {
		line, _ := reader.ReadString('\n')
		if len(line) == 0 {
			break
		}
		split := strings.Split(line, " ")
		row, _ := strconv.Atoi(split[0])
		col, _ := strconv.Atoi(split[1])
		value, _ := strconv.Atoi(strings.Trim(split[2], "\r\n"))
		sp := Sparse{
			Row:   row,
			Col:   col,
			Value: value,
		}
		slice = append(slice, sp)
	}
	return slice
}

// readTwoDimensionArrayFromDisk
//
//	@Description: 从磁盘读取二维数组
//	@param path
//	@return [11][11]int
func readTwoDimensionArrayFromDisk(path string) [11][11]int {
	var arr [11][11]int
	file, err := os.OpenFile(path, os.O_RDONLY, 0666)
	if err != nil {
		fmt.Println("open file err=", err)
		return arr
	}
	defer file.Close()
	reader := bufio.NewReader(file)
	for {
		line, _ := reader.ReadString('\n')
		if len(line) == 0 {
			break
		}
		split := strings.Split(line, " ")
		row, _ := strconv.Atoi(split[0])
		col, _ := strconv.Atoi(split[1])
		value, _ := strconv.Atoi(strings.Trim(split[2], "\r\n"))
		if row == 11 && col == 11 && value == 0 {
			continue
		}
		arr[row][col] = value
	}
	return arr
}

type Sparse struct {
	Row   int
	Col   int
	Value int
}
